package cn.bigfire.wedesk.store;

import cn.bigfire.wedesk.bean.Wedesk;
import cn.bigfire.wedesk.net.protocol.Protocol;
import cn.bigfire.wedesk.service.bo.Context;
import cn.bigfire.wedesk.service.bo.CustInfo;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.concurrent.FastThreadLocal;

import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class Threads {

    //业务线程池
    private static final EventExecutorGroup businessThreadPool = new DefaultEventExecutorGroup(30, r -> {
        Thread thread = new Thread(r);
        thread.setName(String.format("[businessThread-%s]", thread.getId()));
        return thread;
    });

    //ChannelId和线程的绑定关系
    private static final ConcurrentHashMap<String, EventExecutor> channelThreadMap = new ConcurrentHashMap<>();//<channelId,线程>
    //channel广播组
//    private static final ChannelGroup broadcast_ = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    //单个channel
    private static final ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>();

    public static void bindContext(ChannelHandlerContext ctx){
        Channel channel = ctx.channel();
        String channelId = channel.id().asLongText();
        //1注册到广播里
//        broadcast_.add(channel);
        //2根据channelId绑定Channel
        channelMap.put(channelId, channel);
        //3构建自己的Context对象，并绑定到channel上
        ctx.channel().attr(AttributeKey.valueOf(channelId)).set(new Context(ctx));//channelId 绑定 Context
        //4匹配线程
        EventExecutor userExecutor = channelThreadMap.getOrDefault(channelId, businessThreadPool.next());
        channelThreadMap.putIfAbsent(channelId, userExecutor);
    }

    public static EventExecutor getEventExecutor(ChannelHandlerContext ctx){
        Channel channel = ctx.channel();
        String channelId = channel.id().asLongText();
        EventExecutor userExecutor = channelThreadMap.getOrDefault(channelId, businessThreadPool.next());
        channelThreadMap.putIfAbsent(channelId, userExecutor);
        return userExecutor;
    }

    public static void removeContext(ChannelHandlerContext ctx){
        Channel channel = ctx.channel();
        String channelId = channel.id().asLongText();

        //0.如果当前 channelId 有控制别人, 要给别人发消息，不控制了。
        Stores.closeMyCtrl(channelId);

        //1.广播移除
//        broadcast_.remove(channel);
        //2.移除channelId绑定的Channel
        channelMap.remove(channelId);
        //3移除线程信息
//        Context context = (Context)ctx.channel().attr(AttributeKey.valueOf(channelId)).get();
        ctx.channel().attr(AttributeKey.valueOf(channelId)).set(null);//channelId 移除 Context 绑定关系
        //4移除线程信息
        channelThreadMap.remove(channelId);
        //5移除设备信息
        Stores.removePcInfo(channelId);
    }

    //请求时控制线程和Context进行绑定
    private static final FastThreadLocal<Context> contextThreadLocal = new FastThreadLocal<>();

    public static Context getContext(){
        return contextThreadLocal.get();
    }

    public static void setContext(ChannelHandlerContext ctx, int cmd) {
        String channelId = ctx.channel().id().asLongText();
        Context context = (Context) ctx.channel().attr(AttributeKey.valueOf(channelId)).get();
        context.setCmd(cmd);
        contextThreadLocal.set(context);
    }

    public static void removeContext() {
        contextThreadLocal.remove();
    }

    //登录之后才会有custInfo信息

    public static CustInfo getCustInfo(){
        return getContext().getCustInfo();
    }

    public static String getChannelId() {
        return getContext().getChannelId();
    }

    public static Channel getChannel(String channelId) {
        return channelMap.get(channelId);
    }

    public static HashSet<String> onlineChannelIds(){
        return new HashSet<>(channelMap.keySet());
    }

}
